package ca.ubc.eece310.project;

/**
 * EECE 310 Term Project Fall 2009
 * @author Matthew Fong, Herman Lee, Scott Pearson
 */

import java.awt.*;
import java.awt.event.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;

import javax.swing.BorderFactory;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.BoxLayout;
import javax.swing.JTable;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class Gui extends JPanel {
	/**
	 * OVERVIEW: The Gui class creates the main window for the program. It has 
	 * 			 a menubar displaying File->Exit, and Help->About. Below, it has an
	 * 			 information bar displaying the IP address, units of speed,
	 * 			 network interface selection, and total upload and download speed.
	 * 			 Below that, there are 4 tabs, one which displays the speed for each
	 * 			 process, one for graphing the total upload/download speeds, one for 
	 * 			 the logs, and one for the projected usage.
	 */
	private static final long serialVersionUID = 1674744443074030159L;

	private static JScrollPane scrollPane, scrollPaneDay, scrollPaneMonth, scrollPaneYear;
	private static JTable table, tableDay, tableMonth, tableYear;
	private static ProcessTableModel tableData;
	private static JPanel programPanel, projected;
	private static JLabel totalDown, totalUp, ip, subnetMask;
	private static JLabel projectUpToday, projectDownToday, projectTotalToday;
	private static JLabel currentUpToday, currentDownToday, currentTotalToday;
	private static JLabel projectUpMonth, projectDownMonth, projectTotalMonth;
	private static JLabel currentUpMonth, currentDownMonth, currentTotalMonth;
	private static JLabel projectUpYear, projectDownYear, projectTotalYear;
	private static JLabel currentUpYear, currentDownYear, currentTotalYear;
	protected static JFrame frame;
	public static JComboBox units, device;

	private static XYSeries downSeries = new XYSeries("Download speed");
	private static XYSeries upSeries = new XYSeries("Upload speed");
	private static XYSeriesCollection dataSet;
	private final static int maxDataSeries = 25;
	private static int time = 0;
	private static DecimalFormat format = new DecimalFormat("##.###");

	public Gui() {
		super(new BorderLayout());

		// A border that puts 5 extra pixels at the sides and bottom of each pane.
		Border paneEdge = BorderFactory.createEmptyBorder(5, 5, 5, 5);

		JPanel body = new JPanel();
		body.setLayout(new BorderLayout()); 
		// Set up the top little information bar
		JPanel top = new JPanel();
		JPanel topLeftLeft = new JPanel();
		BoxLayout bltll = new BoxLayout(topLeftLeft, BoxLayout.Y_AXIS);
		JPanel topLeft = new JPanel();
		BoxLayout bltl = new BoxLayout(topLeft, BoxLayout.Y_AXIS);
		JPanel topRight = new JPanel();
		BoxLayout bltr = new BoxLayout(topRight, BoxLayout.Y_AXIS);
		topLeftLeft.setLayout(bltll);
		topLeft.setLayout(bltl);
		topRight.setLayout(bltr);

		URL url = null;
		try {
			url = new URL("http://rkmh.ca:8080/eece310/logo.php");
		} catch (MalformedURLException e) {}
		ImageIcon icon = new ImageIcon(url);
		// get the hostname
		JLabel hostname = new JLabel(CommandExecutor.getHostname() + " ");
		hostname.setIcon(icon);
		Font font = new Font("Arial", Font.BOLD, 12);
		hostname.setFont(new Font("Arial", Font.BOLD, 30));
		topLeftLeft.add(hostname);

		// get the total upload and download speed
		totalUp = new JLabel("UL: " + format.format(BandwidthLog.totalUp));
		totalUp.setFont(font);
		totalDown = new JLabel("DL: " + format.format(BandwidthLog.totalDown));
		totalDown.setFont(font);
		topLeft.add(totalDown);
		topLeft.add(totalUp);
		ip = new JLabel("IP Address: " + BandwidthLog.ip);
		ip.setFont(font);
		subnetMask = new JLabel("Subnet Mask: " + BandwidthLog.subnetmask);
		subnetMask.setFont(font);
		topLeft.add(ip); 

		// unit select combobox
		JPanel asdf = new JPanel();
		String[] unitStrings = { "B/s", "KiB/s", "MiB/s" };
		units = new JComboBox(unitStrings);
		units.setSelectedIndex(1);
		units.setFont(font);
		asdf.add(units);
		topRight.add(asdf);
		String[] deviceStrings = new String[BandwidthLog.getDevices().size()];
		for (int i = 0; i < deviceStrings.length; i++) {
			String deviceString = BandwidthLog.getDevices().get(i).toString();
			deviceStrings[i] = deviceString.substring(deviceString
					.indexOf("desc=")
					+ "desc=".length(), deviceString.indexOf(">"));

		}
		asdf = new JPanel();
		device = new JComboBox(deviceStrings);
		device.setSelectedIndex(0);
		device.setMaximumSize(new Dimension(5, 5));
		device.setFont(font);
		asdf.add(device);
		topRight.add(asdf);

		top.add(topLeftLeft);
		top.add(topLeft);
		top.add(topRight);

		// begin tabs
		
		// process tab
		programPanel = new JPanel();
		programPanel.setBorder(paneEdge);
		programPanel.setLayout(new BoxLayout(programPanel, BoxLayout.Y_AXIS));

		// table data for the table
		tableData = new ProcessTableModel();
		table = new JTable(tableData);

		table.setPreferredScrollableViewportSize(new Dimension(500, 200));
		table.setFillsViewportHeight(true);
		scrollPane = new JScrollPane(table);
		programPanel.add(scrollPane);

		// traffic tab
		JPanel traffic = new JPanel();
		traffic.setBorder(paneEdge);
		traffic.setLayout(new BoxLayout(traffic, BoxLayout.Y_AXIS));

		// data series for the chart
		downSeries.setMaximumItemCount(maxDataSeries);
		upSeries.setMaximumItemCount(maxDataSeries);

		// data series collection for the chart
		dataSet = new XYSeriesCollection();
		dataSet.addSeries(downSeries);
		dataSet.addSeries(upSeries);

		// initialize the chart
		JFreeChart chart = ChartFactory.createXYLineChart("", // chart title
				"Time", // x axis label
				"Speed", // y axis label
				dataSet, // data
				PlotOrientation.VERTICAL, true, // include legend
				true, // tooltips
				false // urls
				); 
		ChartPanel chartPanel = new ChartPanel(chart);
		traffic.add(chartPanel);
		
		// log tab
		
		// create tab panels for each log delineation
		JPanel logDay = new JPanel();
		JPanel logMonth = new JPanel();
		JPanel logYear = new JPanel();
		logDay.setBorder(paneEdge);
		logDay.setLayout(new BoxLayout(logDay, BoxLayout.Y_AXIS));
		logMonth.setBorder(paneEdge);
		logMonth.setLayout(new BoxLayout(logMonth, BoxLayout.Y_AXIS));
		logYear.setBorder(paneEdge);
		logYear.setLayout(new BoxLayout(logYear, BoxLayout.Y_AXIS));

		// create tables for each 
		tableDay = new JTable(Log.dayLogData);
		tableMonth = new JTable(Log.monthLogData);
		tableYear = new JTable(Log.yearLogData);
		tableDay.setPreferredScrollableViewportSize(new Dimension(500, 200));
		tableDay.setFillsViewportHeight(true);
		tableMonth.setPreferredScrollableViewportSize(new Dimension(500, 200));
		tableMonth.setFillsViewportHeight(true);
		tableYear.setPreferredScrollableViewportSize(new Dimension(500, 200));
		tableYear.setFillsViewportHeight(true);
		scrollPaneDay = new JScrollPane(tableDay);
		scrollPaneMonth = new JScrollPane(tableMonth);
		scrollPaneYear = new JScrollPane(tableYear);
		logDay.add(scrollPaneDay);
		logMonth.add(scrollPaneMonth);
		logYear.add(scrollPaneYear);
 
		// add the panels to the log tabs
		JTabbedPane logTabbedPane = new JTabbedPane();
		logTabbedPane.addTab("Day", null, logDay, null);
		logTabbedPane.addTab("Month", null, logMonth, null);
		logTabbedPane.addTab("Year", null, logYear, null);
		
		// process tab
		projected = new JPanel();
		projected.setBorder(paneEdge);
		//projected.setLayout(new BoxLayout(programPanel, BoxLayout.Y_AXIS));
		projected.setLayout(new BoxLayout(projected, BoxLayout.Y_AXIS));
		TitledBorder todayBorder = BorderFactory.createTitledBorder("Today");
		JPanel todayPanel = new JPanel(new GridLayout(3, 4));
		todayPanel.setMaximumSize(new Dimension(600, 80));
		todayPanel.setBorder(todayBorder);
		todayPanel.add(new JLabel());
		todayPanel.add(new JLabel("Download:"));
		todayPanel.add(new JLabel("Upload:"));
		todayPanel.add(new JLabel("Total:"));
		todayPanel.add(new JLabel("Current"));
		currentUpToday = new JLabel(BandwidthLog.currentProjectedToday()[0]+" ");
		todayPanel.add(currentUpToday);
		currentDownToday = new JLabel(BandwidthLog.currentProjectedToday()[1]+" ");
		todayPanel.add(currentDownToday);
		currentTotalToday = new JLabel(BandwidthLog.currentProjectedToday()[2]+" ");
		todayPanel.add(currentTotalToday);
		todayPanel.add(new JLabel("Projected"));
		projectUpToday = new JLabel(BandwidthLog.currentProjectedToday()[4]+" ");
		todayPanel.add(projectUpToday);
		projectDownToday = new JLabel(BandwidthLog.currentProjectedToday()[5]+" ");
		todayPanel.add(projectDownToday);
		projectTotalToday = new JLabel(BandwidthLog.currentProjectedToday()[5]+" ");
		todayPanel.add(projectTotalToday);
		
		projected.add(todayPanel);

		TitledBorder monthBorder = BorderFactory.createTitledBorder("This Month");
		JPanel monthPanel = new JPanel(new GridLayout(3, 4));
		monthPanel.setMaximumSize(new Dimension(600, 80));
		monthPanel.setBorder(monthBorder);
		monthPanel.add(new JLabel());
		monthPanel.add(new JLabel("Download:"));
		monthPanel.add(new JLabel("Upload:"));
		monthPanel.add(new JLabel("Total:"));
		monthPanel.add(new JLabel("Current"));
		currentUpMonth = new JLabel(BandwidthLog.currentProjectedMonth()[0]+" ");
		monthPanel.add(currentUpMonth);
		currentDownMonth = new JLabel(BandwidthLog.currentProjectedMonth()[1]+" ");
		monthPanel.add(currentDownMonth);
		currentTotalMonth = new JLabel(BandwidthLog.currentProjectedMonth()[2]+" ");
		monthPanel.add(currentTotalMonth);
		monthPanel.add(new JLabel("Projected"));
		projectUpMonth = new JLabel(BandwidthLog.currentProjectedMonth()[3]+" ");
		monthPanel.add(projectUpMonth);
		projectDownMonth = new JLabel(BandwidthLog.currentProjectedMonth()[4]+" ");
		monthPanel.add(projectDownMonth);
		projectTotalMonth = new JLabel(BandwidthLog.currentProjectedMonth()[5]+" ");
		monthPanel.add(projectTotalMonth);
		projected.add(monthPanel);
		
		TitledBorder yearBorder = BorderFactory.createTitledBorder("This Year");
		JPanel yearPanel = new JPanel(new GridLayout(3, 4));
		yearPanel.setMaximumSize(new Dimension(600, 80));
		yearPanel.setBorder(yearBorder);
		yearPanel.add(new JLabel());
		yearPanel.add(new JLabel("Download:"));
		yearPanel.add(new JLabel("Upload:"));
		yearPanel.add(new JLabel("Total:"));
		yearPanel.add(new JLabel("Current"));
		currentUpYear = new JLabel(BandwidthLog.currentProjectedYear()[0]+" ");
		yearPanel.add(currentUpYear);
		currentDownYear = new JLabel(BandwidthLog.currentProjectedYear()[1]+" ");
		yearPanel.add(currentDownYear);
		currentTotalYear = new JLabel(BandwidthLog.currentProjectedYear()[2]+" ");
		yearPanel.add(currentTotalYear);
		yearPanel.add(new JLabel("Projected"));
		projectUpYear = new JLabel(BandwidthLog.currentProjectedYear()[3]+" ");
		yearPanel.add(projectUpYear);
		projectDownYear = new JLabel(BandwidthLog.currentProjectedYear()[4]+" ");
		yearPanel.add(projectDownYear);
		projectTotalYear = new JLabel(BandwidthLog.currentProjectedYear()[5]+" ");
		yearPanel.add(projectTotalYear);
		projected.add(yearPanel);
		
		// add all the panels to the main tabs
		JTabbedPane tabbedPane = new JTabbedPane();
		tabbedPane.addTab("Program", null, programPanel, null);
		tabbedPane.addTab("Traffic", null, traffic, null);
		tabbedPane.addTab("Log", null, logTabbedPane, null);
		tabbedPane.addTab("Projected", null, projected, null);
		tabbedPane.setSelectedIndex(0);
		String toolTip = "Process Information";
		tabbedPane.setToolTipTextAt(0, toolTip);
		toolTip = "Traffic Graph";
		tabbedPane.setToolTipTextAt(1, toolTip);
		toolTip = "Bandwidth Used in the Past";
		tabbedPane.setToolTipTextAt(2, toolTip);
		toolTip = "How much will be used if the current usage trend continues";
		tabbedPane.setToolTipTextAt(3, toolTip);
		
		body.add(top, BorderLayout.NORTH);
		body.add(tabbedPane, BorderLayout.CENTER);
		add(body);

	}

	public static void update() {
		/**
		 * MODIFIES: totalUp, totalDown, upSeries, downSeries, tableData, ip, subnetMask, time
		 * EFFECTS: Updates the components in the modifies value to current values
		 */
		
		// update the upload and download labels
		totalUp.setText("UL: " + format.format(BandwidthLog.totalUp));
		totalDown.setText("DL: " + format.format(BandwidthLog.totalDown));

		// update the chart, but make sure the numbers are not messed up
		if (BandwidthLog.totalUp != Double.POSITIVE_INFINITY
				&& BandwidthLog.totalUp != Double.NEGATIVE_INFINITY
				&& BandwidthLog.totalUp != Double.NaN
				&& BandwidthLog.totalDown != Double.POSITIVE_INFINITY
				&& BandwidthLog.totalDown != Double.NEGATIVE_INFINITY
				&& BandwidthLog.totalDown != Double.NaN) {
			upSeries.add(time, Math.floor(BandwidthLog.totalUp));
			downSeries.add(time, Math.floor(BandwidthLog.totalDown));
		}
		
		// get the process table to update and tell its listener
		tableData.updateTable();
		tableData.fireTableDataChanged();
		
		// update the ip and subnetmask in case the device changed
		ip.setText("IP Address: " + BandwidthLog.ip);
		subnetMask.setText("Subnet Mask: " + BandwidthLog.subnetmask);
		currentUpToday.setText(BandwidthLog.currentProjectedToday()[0]);
		currentDownToday.setText(BandwidthLog.currentProjectedToday()[1]);
		currentTotalToday.setText(BandwidthLog.currentProjectedToday()[2]);
		projectUpToday.setText(BandwidthLog.currentProjectedToday()[3]);
		projectDownToday.setText(BandwidthLog.currentProjectedToday()[4]);
		projectTotalToday.setText(BandwidthLog.currentProjectedToday()[5]);
		currentUpMonth.setText(BandwidthLog.currentProjectedMonth()[0]);
		currentDownMonth.setText(BandwidthLog.currentProjectedMonth()[1]);
		currentTotalMonth.setText(BandwidthLog.currentProjectedMonth()[2]);
		projectUpMonth.setText(BandwidthLog.currentProjectedMonth()[3]);
		projectDownMonth.setText(BandwidthLog.currentProjectedMonth()[4]);
		projectTotalMonth.setText(BandwidthLog.currentProjectedMonth()[5]);
		currentUpYear.setText(BandwidthLog.currentProjectedYear()[0]);
		currentDownYear.setText(BandwidthLog.currentProjectedYear()[1]);
		currentTotalYear.setText(BandwidthLog.currentProjectedYear()[2]);
		projectUpYear.setText(BandwidthLog.currentProjectedYear()[3]);
		projectDownYear.setText(BandwidthLog.currentProjectedYear()[4]);
		projectTotalYear.setText(BandwidthLog.currentProjectedYear()[5]);
		time++;
	}

	public static void createAndShowGUI() {
		/**
		 * MODIFIES: frame
		 * EFFECTS: Creates the main GUI and shows it
		 */
		// Create and set up the window.
		frame = new GuiFrame("JBandwidth Logger");
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				saveAndClose();
			}
		});

		// Create and set up the content pane.
		Gui newContentPane = new Gui();
		newContentPane.setOpaque(true); // content panes must be opaque
		frame.setContentPane(newContentPane);

		// Display the window.
		frame.pack();
		frame.setSize(new Dimension(900, 500));
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
	}

	public static void saveAndClose() {
		/**
		 * EFFECTS: Saves the log and exits.
		 */
		Log.save();
		System.exit(0);

	}
}

class GuiFrame extends JFrame {
	/**
	 * OVERVIEW: Custom frame with ActionListener and menubar
	 */

	private static final long serialVersionUID = -4559490297634030176L;

	public class ButtonListener implements ActionListener {
		/**
		 * OVERVIEW: Custom ActionListener
		 */
		public void actionPerformed(ActionEvent e) {
			/**
			 * REQUIRES: e != null
			 * EFFECTS: Is run when an event occurs
			 * 			Closes frame when e.getActionCommand() is exit
			 * 			Displays help when e.getActionCommand() is help contents
			 * 			Displays about when e.getActionCommand() is about
			 */
			if (e.getActionCommand().equals("Exit")) {
				Gui.saveAndClose();
			} else if (e.getActionCommand().equals("About")) {
				Icon icon = new ImageIcon("images/icon_80x80.png");

				JOptionPane.showMessageDialog( Gui.frame,
						"JBandwidth Monitor\n (c) 2009 Matthew Fong, Herman Lee, Scott Pearson",
						"About", 0, icon);

			}
		}
	}


	private JMenuBar MyMenuBar(ActionListener act) {
		/**
		 * REQUIRES: act != null
		 * EFFECTS: Creates a menubar with File -> Exit
		 * 								   Help -> Help Contents
		 * 										-> About
		 */ 
		JMenuItem menuItem;
		JMenuBar menuBar;
		JMenu menu;
 
		menuBar = new JMenuBar();
 
		menu = new JMenu("File");
		menu.setMnemonic(KeyEvent.VK_F);
		menuBar.add(menu);
 
		menuItem = new JMenuItem("Exit", KeyEvent.VK_E);
		menuItem.addActionListener(act);
		menu.add(menuItem);

		add(menuBar);

		menu = new JMenu("Help");
		menu.setMnemonic(KeyEvent.VK_H);
		menuBar.add(menu);
		
		menuItem = new JMenuItem("About", KeyEvent.VK_A);
		menuItem.addActionListener(act);
		menu.add(menuItem);

		add(menuBar, BorderLayout.NORTH);

		return menuBar;
	}

	public GuiFrame(String s) {
		super(s);
		setJMenuBar(MyMenuBar(new ButtonListener()));

	}

}
